타입변환

이 노트는 C++의 값 타입 변환과 참조 타입 변환의 차이, 업캐스팅/다운캐스팅, 암시적/명시적 변환, 그리고 연관 없는 클래스 사이·상속 관계 클래스 사이의 타입 변환을 정리한다. 핵심은 상속 관계에서 자식→부모 변환(값·참조 모두)은 1:1로 대응되어 항상 가능하지만, 부모→자식 값 변환은 자식에만 있는 멤버 때문에 캐스팅이 불가능하고, 참조로 강제 변환하면 컴파일은 되어도 메모리 침범 위험이 있다는 점이다.

  1. 일반적인 값& 참조타입 변환
  2. 업캐스팅 & 다운캐스팅       
  3. 암시적 변환 & 명시적 변환  
  4. 아무 관계없는 클래스 사이의 변환
  5. 상속관계의 클래스 타입 변환

일반적인 값& 참조타입 변환

  • 값 타입 변환
    • 원본 객체와 다른 비트열 재구성

int a = 1234567;
float b = (float)a; // 비트열 재구성 -> 값의 오류가 생길 수 있음

  • 참조 타입 변환
    • 비트열 재구성 x , 관점만 변환

int a = 1234567;
float b = (float&)a; // a의 주소값을 float으로 이해하겠다라는 의미 (값의 변형이 존재)
// float b = (float)&a; // 동일한 표현

업캐스팅 & 다운캐스팅

  • 업캐스팅
    • 작은 것 -> 큰 것으로 변경
    • 더 많은 범위를 표현할 수 있는 타입으로 변경하기에 문제가 되지 않는다

int a = 1234567; // int = 4바이트
__int64 b = a; // __int64 = 8바이트
doublc c = a; // double = 8바이트

  • 다운캐스팅
    • 큰 것 -> 작은 것으로 변경
    • 값의 범위를 초과하므로 제대로된 값을 표현하지 못할 수 있다.

int a = 12345678;
short b = a; // short = 1바이트

암시적 변환 & 명시적 변환

  • 암시적 변환

    • 컴파일러가 알아서 캐스팅해주는 변환
  • 명시적 변환

    • 프로그래머의 의도에 따라 캐스팅해주는 변환

아무 관계없는 클래스 사이의 변환

class Knight
{
public:
	int _hp;
	int _attack;
};
 
class Dog
{
public:
	Dog()
	{
 
	}
	Dog(const Knight& knight)
	{
		_hp = knight._hp;
	}
 
	operator Knight()
	{
		return (Knight)(*this);
	}
public:
 
	int listen;
	int _hp;
	int _mp;
};
  • 타입 변환 생성자
    • Dog(const Knight& knight)
      • 타입변환 생성자를 이용하여 Dog를 생성할 수 있도록 명시
  • 타입 변환 연산자
    • operator Knight()
      • 타입변환 연산자를 이용하여 return 값으로 Knight로 명시적 캐스팅하여 전달
{
	Knight knight;
	Dog dog(knight); // 타입변환 생성자
	//Dog dog = knight; // 타입변환 생성자 또다른 선언
 
	Knight knight2 = dog; // 타입변환 연산자
 
}
 
// [2] 연관없는 클래스 사이의 참조 타입 변환 (주소이므로, 명시적으로 하면 일단은 통과는 한다)
{
	Knight knight;
	Dog& dog = (Dog&)knight;
	dog.listen = 2; // 이상한 메모리를 건들게 된다
}

상속관계의 클래스 타입 변환

class Dog
{
public:
	Dog()
	{
 
	}
	
public:
 
	int listen;
	int _hp;
	int _mp;
};
 
class BullDog : public Dog
{
public:
	bool _french;
};
  • 각 클래스가 가지고 있는 메모리 크기
BullDoglisten , _hp, _mp , _french
Doglisten, _hp, _mp
    • 상속관계 클래스의 값 타입 변환
      • 부모 -> 자식 
        • BullDog bulldog = (BullDog)dog; //캐스팅 불가
        • 개는 불독이다 ( 개는 불독일수도 있고 , 아닐수도 있기에)
        • Dog에는 _french라는 변수가 없으므로 1:1 대응이 되지 않아 암시적/명시적 캐스팅 불가능 
      • 자식  -> 부모
        • Dog dog = bulldog; // 캐스팅 가능
        • 불독은 개이다 (불독은 개가 맞음)
        • 1:1 매칭 가능
    • 상속관계 클래스의 참조 타입 변환
      • 부모 -> 자식
        • BullDog& bulldog = (BullDog&) dog; // 캐스팅 가능
        • 참조타입으로 넘기므로, 캐스팅은 가능하나 메모리 침범이 일어날 수 있다.
      • 자식 -> 부모
        • Dog& dog = bulldog; // 캐스팅 가능
        • 참조타입으로 넘기더라도, BullDog메모리에 Dog영역을 가지고 있기에 문제가 없다